<cfcomponent name="NaNoWriMoGateway" extends="Gateway" hint="Proxy to NaNoWriMo services" namespace="com.nowrists" output="false">
	<cffunction name="UserInfo" access="remote" output="false" returntype="query">
		<cfargument name="UID" type="numeric" required="true">
		<cfset var NeedToFetch=true>
		<cfset var Data="">
		<cfset var UserInfo="">
		<cfset var i="">
		<cfset var ColName="">
		<cfset var ColType="">
		<cfset var Buddy="">
		<cfset var Daily="">
		<cfset IsValidXML=True>
		<cflock name="NaNoWriMoGateway2007_UserInfo_#Arguments.UID#" type="exclusive" timeout="30">
			<cfquery datasource="#Variables.DSN2007#" name="FindUID">
			SELECT uid, username, fetch_date AS FetchDate, location, wordcount, donor, noveltitle, genre, photo, region, home_region_node, age, website, joined_date, yearsdone, yearswon, postcount, buddy_count, wordcount_xml_name, wordcount_xml, daily, winner
			FROM nws_nano_userinfo_2007
			WHERE (uid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#Arguments.UID#">)
			</cfquery>
			<cfif (FindUID.RecordCount EQ 1) AND IsDate(FindUID.FetchDate) AND (DateAdd("h",2,FindUID.FetchDate) GTE Now())>
				<cfset NeedToFetch=false>
			</cfif>
			<cfif NeedToFetch>
				<cftry>
					<cfhttp method="get" url="http://www.nanowrimo.org/eng/user/#Arguments.UID#" useragent="Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"></cfhttp>
					<cfset Data=ReReplaceNoCase(CFHTTP.FileContent,"&##0*39;","'","ALL")>
					<cfset Data=ReReplaceNoCase(Data,"&##[0-9a-f]+;","","ALL")>
					<cfset UserInfo=parseUserInfo(Data,FindUID.columnList)>
					<!--- <cffile action="READ" file="#ExpandPath('./test.html')#" variable="data"> --->
					<!--- <cfset UserInfo=parseUserInfo(data,FindUID.columnList)> --->
					<cfset UserInfo["wordcount_xml"]="">
					<cfset isValidXML=false>
					<cfif (UserInfo.wordcount_xml_name neq "") and isNumeric(UserInfo["wordcount"]) and (UserInfo["wordcount"] gt 0)>
						<cfhttp method="get" url="http://www.nanowrimo.org/files/main/swfcharts/#UserInfo.wordcount_xml_name#" useragent="Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"></cfhttp>
						<!--- <cfset Data=CFHTTP.FileContent> --->
						<cfset Data=ReReplaceNoCase(CFHTTP.FileContent,"&##[0-9a-f]+;","","ALL")>
						<!--- <cffile action="READ" file="#ExpandPath('./test.xml')#" variable="data"> --->
						<cfif (len(Data) gt 0) and left(Data,7) eq "<chart>">
							<cftry>
								<cfset Data=XMLParse(Data)>
								<cfset UserInfo["wordcount_xml"]=data>
								<cfset data=xmlSearch(data,"/chart/chart_data/row[2]/number/text()")>
								<cfif isArray(data)>
									<cfloop from="1" to="#arrayLen(data)#" index="i">
										<cfif (i lte arrayLen(data)) and isNumeric(data[i].xmlValue)>
											<cfset Daily=Daily & data[i].xmlValue>
										</cfif>
										<cfset Daily=Daily & ",">
									</cfloop>
								</cfif>
								<cfcatch>
									<cfset Daily="">
								</cfcatch>
							</cftry>
						</cfif>
					</cfif>
					<cfif isNumeric(UserInfo.WordCount)>
						<cfset UserInfo["daily"]=Daily>
						<cfif FindUID.RecordCount EQ 0>
							<cfquery datasource="#Variables.DSN2007#">
							INSERT INTO nws_nano_userinfo_2007 (uid, fetch_date)
							VALUES (<cfqueryparam cfsqltype="cf_sql_integer" value="#Arguments.UID#">, GETDATE() )
							</cfquery>
						</cfif>
						<cfquery datasource="#Variables.DSN2007#">
						UPDATE nws_nano_userinfo_2007
						SET 
							<cfloop list="username:VARCHAR,location:VARCHAR,wordcount:INTEGER,donor:INTEGER,noveltitle:VARCHAR,genre:VARCHAR,photo:VARCHAR,region:VARCHAR,home_region_node:INTEGER,age:INTEGER,website:VARCHAR,joined_date:DATE,yearsdone:VARCHAR,yearswon:VARCHAR,postcount:INTEGER,buddy_count:INTEGER,wordcount_xml_name:VARCHAR,wordcount_xml:LONGVARCHAR,daily:LONGVARCHAR,winner:INTEGER" index="ColName">
								<cfset ColType=ListRest(ColName,":")><cfset ColName=ListFirst(ColName,":")>
								<cfswitch expression="#ColType#">
									<cfcase value="VARCHAR,LONGVARCHAR" delimiters=",">
										<cfif UserInfo[colName] neq "">#ColName# = <cfqueryparam cfsqltype="CF_SQL_#colType#" value="#UserInfo[ColName]#">,</cfif>
									</cfcase>
									<cfcase value="INTEGER">
										<cfif IsNumeric(UserInfo[colName])>#ColName# = <cfqueryparam cfsqltype="CF_SQL_#colType#" value="#Int(UserInfo[ColName])#">,</cfif>
									</cfcase>
									<cfcase value="DATE">
										<cfif IsDate(UserInfo[colName])>#ColName# = <cfqueryparam cfsqltype="CF_SQL_#colType#" value="#UserInfo[ColName]#">,</cfif>
									</cfcase>
								</cfswitch>
							</cfloop>
							fetch_date = GETDATE()
						WHERE (uid = <cfqueryparam cfsqltype="CF_SQL_INTEGER" value="#Arguments.UID#">)
						</cfquery>
						<cfif structKeyExists(UserInfo, "buddies") and isQuery(UserInfo.Buddies) and (UserInfo.Buddies.RecordCount gt 0)>
							<cfquery datasource="#Variables.DSN2007#">
							DELETE FROM nws_user_buddies_2007
							WHERE (uid = <cfqueryparam cfsqltype="cf_sql_integer" value="#Arguments.UID#">)
							</cfquery>
							<cfloop query="UserInfo.Buddies">
								<cfquery datasource="#Variables.DSN2007#">
								INSERT INTO nws_user_buddies_2007 (uid, buddy_name, buddy_uid, buddy_wordcount, buddy_donor, buddy_fetchdate)
								VALUES 
									(
										<cfqueryparam cfsqltype="cf_sql_integer" value="#Arguments.UID#">,
										<cfqueryparam cfsqltype="cf_sql_varchar" value="#buddy_name#">,
										<cfqueryparam cfsqltype="cf_sql_integer" value="#buddy_uid#">,
										<cfqueryparam cfsqltype="cf_sql_integer" value="#buddy_wordcount#">,
										<cfqueryparam cfsqltype="cf_sql_integer" value="#buddy_donor#">,
										GETDATE()
									)
								</cfquery>
							</cfloop>
						</cfif>
						<cfquery datasource="#Variables.DSN2007#" name="FindUID">
						SELECT uid, username, fetch_date AS FetchDate, location, wordcount, donor, noveltitle, genre, photo, region, home_region_node, age, website, joined_date, yearsdone, yearswon, postcount, buddy_count, wordcount_xml_name, wordcount_xml, daily, winner
						FROM nws_nano_userinfo_2007
						WHERE (uid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#Arguments.UID#">)
						</cfquery>
					<cfelse>
						<cfabort showerror="NaNo did not return XML data">
					</cfif>
				<cfcatch>
					<cfdump var="#CFCatch#">
					<cfabort>
				</cfcatch>
				</cftry>
			</cfif>
		</cflock>
		<cfreturn FindUID>
	</cffunction>
	<cffunction name="UserFriendsAsQuery" access="public" output="true" returntype="query">
		<cfargument name="UID" type="numeric" required="true">
		<cfargument name="Count" type="numeric" required="false" default="2">
		<cfset var Ret="">
		<cfquery name="Ret" datasource="#Variables.DSN2007#" maxrows="#Arguments.Count#">
		SELECT TOP #Arguments.Count# b.buddy_name AS BuddyName, b.buddy_uid AS BuddyUID, b.buddy_wordcount AS BuddyWordCount, CASE WHEN COALESCE(b.buddy_wordcount,0) >= 50000 THEN 'Winner!' END AS BuddyWinner, f.noveltitle AS BuddyNovelTitle
		FROM nws_user_buddies_2007 AS b
		  INNER JOIN nws_nano_userinfo_2007 AS u ON (b.uid = u.uid)
		  LEFT OUTER JOIN nws_nano_userinfo_2007 AS f ON (b.buddy_uid = f.uid)
		WHERE (b.uid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#Arguments.UID#">)
		ORDER BY ABS(b.buddy_wordcount - u.wordcount), RAND()
		<!--- LIMIT <cfqueryparam cfsqltype="cf_sql_numeric" value="#Arguments.Count#"> --->
		</cfquery>
		<cfreturn Ret>
	</cffunction>
	<cffunction name="FindUserAsQuery" access="remote" output="true" returntype="query">
		<cfargument name="Username" type="string" required="true" >
		<cfargument name="Debug" type="boolean" required="false" default="false">
		<cfset var UName=REReplaceNoCase(Arguments.Username, "[^-a-zA-Z0-9_@. ]","","ALL")>
		<cfset var Result=QueryNew("Username,UID,NovelTitle,HomePage,Location,JoinDate,PostCount,Donor")>
		<cfquery datasource="#Variables.DSN2007#" name="FindUsername">
		SELECT uid, username, fetch_date AS FetchDate, location, wordcount, donor, noveltitle, genre, photo, region, home_region_node, age, website, joined_date, yearsdone, yearswon, postcount, buddy_count, wordcount_xml_name, wordcount_xml, daily
		FROM nws_nano_userinfo_2007
		WHERE <cfif IsNumeric(arguments.Username)>uid = <cfqueryparam cfsqltype="cf_sql_integerr" value="#Arguments.Username#">
		<cfelse>
		(username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Arguments.Username#">)
		</cfif>
		</cfquery>
		<cfif FindUserName.RecordCount EQ 1>
			<cfreturn FindUsername>
		</cfif>
		<cfreturn Result>
	</cffunction>
	<cffunction name="parseUserInfo" access="public" output="false" returntype="struct">
		<cfargument name="content" type="string" required="true">
		<cfargument name="columns" type="string" required="false" default="">
		<cfset var ret=structNew()>
		<cfset var colName="">
		<cfset var html=arguments.content>
		<cfset var at=0>
		<cfset var matches="">
		<cfset var tabContent="">
		<cfset var part="">
		<cfset var buddies=queryNew("buddy_uid,buddy_name,buddy_wordcount,buddy_donor")>
		<cfloop list="#arguments.columns#" index="colName">
			<cfset ret[colName]="">
		</cfloop>
		<cfset ret["buddies"]=buddies>
		<cfset at=find('<!-- *** Sidebar Navigation *** -->',html)>
		<cfif at gt 0><cfset html=mid(html,at,len(html))></cfif>
		<cfset at=find('<!-- END TAB AREA -->',html)>
		<cfif at gt 0><cfset html=left(html,at)></cfif>

		<cfset tabContent=getFirstMatch('^(.*)<!-- END Sidebar Navigation -->',html)>
		<cfif tabContent neq "">
			<cfset html=mid(html, len(tabContent), len(html))>
			<cfset part=getFirstMatch('<div class="NaNoBoxTop">(.*)<div class="authorphoto">',tabContent)>
			<cfif find('<a href="http://store.lettersandlight.org/"><img src="/sites/all/themes/nanowrimo/profile/haloIcon-buddy.gif" align="middle" border="0" alt="Glowing Halo" title="NaNoWriMo Donor" /></a>',part) gt 0>
				<cfset ret["donor"]=1>
			<cfelse>
				<cfset ret["donor"]=0>
			</cfif>
			<cfset ret["photo"]=getFirstMatch('<div class="picture"><a href="[^"]*" title="View user profile." class="active"><img src="([^"]*)"',tabContent)>
			<cfset ret["website"]=getFirstMatch('<a href="([^"]*)"><img src="/sites/all/themes/nanowrimo/profile/external.gif" border="0" /> visit website</a>',tabContent)>
		</cfif>
		<cfset tabContent=getFirstMatch('^(.*)<!-- END TOP AUTHOR BOX -->',html)>
		<cfif tabContent neq "">
			<cfset html=mid(html, len(tabContent), len(html))>
			<cfset ret["username"]=getFirstMatch('<div class="authorname">([^<]*)</div>',tabContent)>
			<cfset ret["noveltitle"]=getFirstMatch('<span class="noveltitle">([^<]*)</span>',tabContent)>
			<cfset ret["genre"]=getFirstMatch('<span class="label">Genre: </span>([^<]*)</div>',tabContent)>
			<cfset ret["wordcount"]=replace(getFirstMatch('<span class="wordssofarNum">([^<]*)</span>',tabContent),",","","ALL")>
			<cfif isNumeric(ret["wordcount"])>
				<cfif (ret["wordcount"] gt 50000)>
					<cfset ret["winner"]=1>
				<cfelse>
					<cfset ret["winner"]=0>
				</cfif>
			</cfif>
		</cfif>
		<cfset tabContent=getFirstMatch('^(.*)<!--END TAB 1-->',html)>
		<cfif tabContent neq "">
			<cfset html=mid(html, len(tabContent), len(html))>
			<cfset ret["location"]=getFirstMatch('<p><span class="label">Location: </span>([^<]*)</p>',tabContent)>
			<cfset part=getFirstMatch('<p><span class="label">Home Region:</span><br /><a href="[^"]*node/([0-9]*">[^<]*)</a></p>',tabContent)>
			<cfset ret["home_region_node"]=listFirst(part,'"')>
			<cfset ret["region"]=listRest(part,'>')>
			<cfset ret["age"]=getFirstMatch('<p><span class="label">Age:</span>([0-9]+)</p>',tabContent)>
			<cfset part=getFirstMatch('<p><span class="label">Joined date:</span>([^<]*)</p>',tabContent)>
			<cfif part neq "">
				<cfset at=listFind("January,February,March,April,May,June,July,August,September,October,November,December",listFirst(part," "))>
				<cfif (at gt 0) and isNumeric(listLast(part," ")) and isNumeric(listFirst(listRest(part," ")))>
					<cfset ret["joined_date"]=createDate(listLast(part," "),at,listFirst(listRest(part," ")))>
				</cfif>
			</cfif>
			<cfset ret["yearsdone"]=getFirstMatch('<p><span class="label">Years done NaNoWriMo:</span> <br />([^<]*)</p>',tabContent)>
			<cfset ret["yearsdone"]=replace(ret["yearsdone"]," | ",",","ALL")>
			<cfset ret["yearswon"]=getFirstMatch('<p><span class="label">Years won NaNoWriMo:</span> <br />([^<]*)</p>',tabContent)>
			<cfset ret["yearswon"]=replace(ret["yearswon"]," | ",",","ALL")>
			<cfset ret["postcount"]=getFirstMatch('<p><span class="label">NaNoWriMo posts:</span> ([0-9]+)</p>',tabContent)>
			<cfset ret["buddy_count"]=getFirstMatch('<p><span class="label">NaNoWriMo buddies:</span> ([0-9]+)</p>',tabContent)>
		</cfif>
		<cfset tabContent=getFirstMatch('^(.*)<!--END TAB 2 -->',html)>
		<cfif tabContent neq "">
			<cfset html=mid(html, len(tabContent), len(html))>
		</cfif>
		<cfset tabContent=getFirstMatch('^(.*)<!--END TAB 3 -->',html)>
		<cfif tabContent neq "">
			<cfset html=mid(html, len(tabContent), len(html))>
			<cfset tabContent=replace(tabContent,'<a href="http://store.lettersandlight.org/"><img src="/sites/all/themes/nanowrimo/profile/haloIcon-buddy.gif" align="middle" border="0" alt="Glowing Halo" title="NaNoWriMo Donor" /></a><br />','<donor 1/>',"ALL")>
			<cfset tabContent=replace(tabContent,' class="buddy"><a',' class="buddy"><donor 0/><a',"ALL")>
			<cfloop condition="len(tabContent) gt 0">
				<cfset matches=reFindNoCase('<td align="right" valign="middle" class="buddy"><donor ([01])/>[[:space:]]*<a href="[^"]*/([0-9]+)">([^<]+)</a></td>[[:space:]]*<td align="left" class="wordcount"><img src="/sites/all/themes/nanowrimo/wordcount/progress_end_l.gif" height="14" /><img src="/sites/all/themes/nanowrimo/wordcount/progress_completed.gif" title="[^"]*" width="[^"]*" height="14" /><img src="/sites/all/themes/nanowrimo/wordcount/progress_remaining.gif" title="[^"]*" width="[^"]*" height="14" /><img src="/sites/all/themes/nanowrimo/wordcount/progress_end_r.gif" height="14" /><br />([0-9,]+) / [0-9,]+</td>',tabContent,1,true)>
				<cfif (arrayLen(matches.pos) eq 5) and (matches.pos[1] gt 0)>
					<cfset queryAddRow(buddies)>
					<cfset querySetCell(buddies, "buddy_donor", mid(tabContent, matches.pos[2], matches.len[2]), buddies.recordCount)>
					<cfset querySetCell(buddies, "buddy_uid", mid(tabContent, matches.pos[3], matches.len[3]), buddies.recordCount)>
					<cfset querySetCell(buddies, "buddy_name", mid(tabContent, matches.pos[4], matches.len[4]), buddies.recordCount)>
					<cfset querySetCell(buddies, "buddy_wordcount", replace(mid(tabContent, matches.pos[5], matches.len[5]),",","","ALL"), buddies.recordCount)>
					<cfset tabContent=mid(tabContent, matches.pos[1] + matches.len[1], len(tabContent))>
				<cfelse>
					<cfset tabContent="">
				</cfif>
			</cfloop>
		</cfif>
		<cfset tabContent=getFirstMatch('^(.*)<!--END TAB 4 -->',html)>
		<cfif tabContent neq "">
			<cfset html=mid(html, len(tabContent), len(html))>
			<cfset ret["wordcount_xml_name"]=getFirstMatch('http://www.nanowrimo.org/sites/all/modules/swfcharts/charts/charts.swf[?]library_path=http://www.nanowrimo.org/sites/all/modules/swfcharts/charts/charts_library&xml_source=http://www.nanowrimo.org/files/main/swfcharts/([A-Za-z0-9]+.xml)',tabContent)>
		</cfif>
		<cfreturn ret>
	</cffunction>
	<cffunction name="getFirstMatch" access="private" output="false" returntype="string">
		<cfargument name="RegEx" type="string" required="true">
		<cfargument name="Corpus" type="string" required="true">
		<cfset var ret="">
		<cfset var matches=REFindNoCase(arguments.regex,arguments.corpus,1,true)>
		<cfif (arrayLen(matches.pos) gt 1) and (matches.len[2] gt 0)>
			<cfset ret=trim(mid(arguments.corpus,matches.pos[2],matches.len[2]))>
		</cfif>
		<cfreturn ret>
	</cffunction>
	<cffunction name="Authenticate" access="remote" output="false" returntype="xml">
		<cfargument name="Username" type="string" required="true">
		<cfargument name="Password" type="string" required="true">
		<!--- TODO: Implement Method --->
		<cfreturn>
	</cffunction>
</cfcomponent>